using System;
using System.Threading;

public static class Program {
   public static void Main(string[] args) {

   }
}

internal sealed class QueueItem { }

internal sealed class Queue {
   private Int32  m_numItems = 0;   // Number of QueueItems in queue
   private Int32  m_numWaiting = 0; // Number of threads calling DequeueItem
   private Object m_lock = new Object();

   // Method to add a QueueItem to the queue
   public void EnqueueItem(QueueItem qi) {
      lock (m_lock) {
         // (Code to add qi to queue goes here...)
         m_numItems++;
         Monitor.Pulse(m_lock); // Wakeup a waiter if one is waiting
      }
   }

   // Method to remove a QueueItem from the queue
   public QueueItem DequeueItem() {
      QueueItem qi = null;
      lock (m_lock) {
         if (m_numItems == 0 || m_numWaiting > 0) {
            // No items, wait for an item
            m_numWaiting++;
            Monitor.Wait(m_lock);
            m_numWaiting--;
         }
         // (Code to remove a QueueItem goes here...)
         m_numItems--;
      }
      return qi;
   }
}

internal sealed class QueueWithKernelObjects {
   // Allows mutual-exclusive access to the Q's data structures
   Mutex QAccess = new Mutex();

   // Indicates the number of items in the queue (initialized to 0)
   Semaphore QNotEmpty = new Semaphore(0, Int32.MaxValue);

   public void EnqueueItem(QueueItem qi) {
      QAccess.WaitOne();            // Obtain exclusive access
      // Add the QueueItem (qi) to the queue...
      QNotEmpty.Release();          // Increment number of items
      QAccess.ReleaseMutex();       // Release exclusive access
   }

   public QueueItem DequeueItem() {
      QueueItem qi = null;

      // Wait until there is at least 1 item in the queue
      // and until we can get exclusive access to the queue
      WaitHandle.WaitAll(new WaitHandle[] { QAccess, QNotEmpty });

      // Remove a QueueItem (qi) from the queue...

      QAccess.ReleaseMutex();       // Release exclusive access
      return qi;
   }
}
